"""
独立可迁移的模型提供者工具类。

目标：
- 提供统一的 BaseProvider 抽象类
- ModelProvider 管理器：根据场景选择 provider 与 model
- 默认实现（骨架）包括 Moonshot / Deepseek / Aliyun 百炼

设计要点：
- 不包含项目特定依赖，可拷贝到其它仓库
- 通过环境变量配置 base_url 与 api_key
- 提供 send_message() 方法作为对话模型调用入口（可被覆盖）
"""
from __future__ import annotations

import os
import time
from abc import ABC, abstractmethod
from typing import Any, Dict, Optional

import requests


class ProviderError(Exception):
    pass


class BaseProvider(ABC):
    """抽象提供者。

    子类应实现 send_message，实现与具体 API 的交互。
    """

    def __init__(self, name: str, base_url: str, api_key: str, default_model: Optional[str] = None):
        self.name = name
        self.base_url = base_url.rstrip("/") if base_url else ""
        self.api_key = api_key
        self.default_model = default_model

    @abstractmethod
    def send_message(self, model: str, messages: Any, **kwargs) -> Dict[str, Any]:
        """发送对话消息到模型并返回解析后的结果。

        - model: 提供者内的模型标识
        - messages: 对话内容，格式由具体提供者决定（通常是 list/dict）
        - kwargs: 额外可选参数（timeout, headers, params 等）
        """


class MoonshotProvider(BaseProvider):
    """简单实现（骨架）。如需支持更多功能，请扩展 send_message 逻辑。"""

    def send_message(self, model: str, messages: Any, **kwargs) -> Dict[str, Any]:
        if not self.base_url or not self.api_key:
            raise ProviderError("Moonshot provider not configured")

        # 默认构造：POST {base_url}/v1/chat/completions  （具体 path 视实际 API 而定）
        path = kwargs.pop("path", "/v1/chat/completions")
        url = f"{self.base_url}{path}"

        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json",
        }

        payload = {
            "model": model or self.default_model,
            "messages": messages,
        }

        timeout = kwargs.pop("timeout", 15)
        resp = requests.post(url, json=payload, headers=headers, timeout=timeout)
        try:
            resp.raise_for_status()
        except Exception as e:
            raise ProviderError(f"moonshot request failed: {e} - body: {resp.text}")

        return resp.json()


class DeepseekProvider(BaseProvider):
    """Deepseek 提供者骨架实现。"""

    def send_message(self, model: str, messages: Any, **kwargs) -> Dict[str, Any]:
        if not self.base_url or not self.api_key:
            raise ProviderError("Deepseek provider not configured")

        path = kwargs.pop("path", "/v1/chat/completions")
        url = f"{self.base_url}{path}"

        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json",
        }

        payload = {
            "model": model or self.default_model,
            "messages": messages,
        }

        timeout = kwargs.pop("timeout", 15)
        resp = requests.post(url, json=payload, headers=headers, timeout=timeout)
        try:
            resp.raise_for_status()
        except Exception as e:
            raise ProviderError(f"deepseek request failed: {e} - body: {resp.text}")

        return resp.json()


class AliyunProvider(BaseProvider):
    """百炼（阿里云）提供者骨架实现。

    由于不同厂商的 API 格式差异较大，此处保留灵活 payload/paths。
    """

    def send_message(self, model: str, messages: Any, **kwargs) -> Dict[str, Any]:
        if not self.base_url or not self.api_key:
            raise ProviderError("Aliyun provider not configured")

        path = kwargs.pop("path", "/compatible-mode/v1/invoke")
        url = f"{self.base_url}{path}"

        headers = {
            "x-api-key": self.api_key,
            "Content-Type": "application/json",
        }

        payload = {
            "model": model or self.default_model,
            "input": messages,
        }

        timeout = kwargs.pop("timeout", 20)
        resp = requests.post(url, json=payload, headers=headers, timeout=timeout)
        try:
            resp.raise_for_status()
        except Exception as e:
            raise ProviderError(f"aliyun request failed: {e} - body: {resp.text}")

        return resp.json()


class ModelProvider:
    """管理多个 provider，并根据 key/场景选择合适的 provider。

    用法示例：
        mp = ModelProvider()
        resp = mp.send("moonshot", model="kimi-k2-0711-preview", messages=[...])
    """

    def __init__(self, config: Optional[Dict[str, Dict[str, str]]] = None):
        # 从环境变量读取默认配置（如果未传入 config）
        self.config = config or self._load_config_from_env()
        self.providers: Dict[str, BaseProvider] = {}
        self._init_providers()

    def _load_config_from_env(self) -> Dict[str, Dict[str, str]]:
        # 约定环境变量名（小写或大写，常见配置）
        return {
            "moonshot": {
                "base_url": os.getenv("MOONSHOT_BASE_URL") or os.getenv("moonshot_BASE_URL"),
                "api_key": os.getenv("MOONSHOT_API_KEY") or os.getenv("moonshot_API_KEY"),
                "default_model": os.getenv("MOONSHOT_DEFAULT_MODEL") or os.getenv("moonshot_DEFAULT_MODEL"),
            },
            "deepseek": {
                "base_url": os.getenv("DEEPSEEK_BASE_URL") or os.getenv("deepseek_BASE_URL"),
                "api_key": os.getenv("DEEPSEEK_API_KEY") or os.getenv("deepseek_API_KEY"),
                "default_model": os.getenv("DEEPSEEK_DEFAULT_MODEL") or os.getenv("deepseek_DEFAULT_MODEL"),
            },
            "aliyun": {
                "base_url": os.getenv("aliyuncsBASE_URL") or os.getenv("ALIYUNCS_BASE_URL"),
                "api_key": os.getenv("aliyuncsAPI_KEY") or os.getenv("ALIYUNCS_API_KEY"),
                "default_model": os.getenv("aliyuncsDEFAULT_MODEL") or os.getenv("ALIYUNCS_DEFAULT_MODEL"),
            },
        }

    def _init_providers(self) -> None:
        c = self.config
        if not c:
            return

        m = c.get("moonshot", {})
        if m.get("base_url") or m.get("api_key"):
            self.providers["moonshot"] = MoonshotProvider("moonshot", m.get("base_url", ""), m.get("api_key", ""), m.get("default_model"))

        d = c.get("deepseek", {})
        if d.get("base_url") or d.get("api_key"):
            self.providers["deepseek"] = DeepseekProvider("deepseek", d.get("base_url", ""), d.get("api_key", ""), d.get("default_model"))

        a = c.get("aliyun", {})
        if a.get("base_url") or a.get("api_key"):
            self.providers["aliyun"] = AliyunProvider("aliyun", a.get("base_url", ""), a.get("api_key", ""), a.get("default_model"))

    def list_providers(self) -> Dict[str, BaseProvider]:
        return self.providers

    def choose_provider(self, provider_name: Optional[str] = None) -> BaseProvider:
        """根据传入的 provider_name 选择 provider；如果未传入，则按优先级选择可用 provider。

        优先级可按需要调整；当前优先级：moonshot -> deepseek -> aliyun
        """
        if provider_name:
            p = self.providers.get(provider_name)
            if not p:
                raise ProviderError(f"provider '{provider_name}' not configured")
            return p

        for name in ("moonshot", "deepseek", "aliyun"):
            p = self.providers.get(name)
            if p:
                return p

        raise ProviderError("no provider configured")

    def send(self, provider: Optional[str] = None, model: Optional[str] = None, messages: Any = None, **kwargs) -> Dict[str, Any]:
        """向选定的 provider 发送消息。

        返回 provider 的 JSON 响应（原样），上层可负责解析。
        """
        p = self.choose_provider(provider)
        model_to_use = model or p.default_model
        if not model_to_use:
            raise ProviderError("no model specified and provider has no default model")

        start = time.time()
        resp = p.send_message(model_to_use, messages or [], **kwargs)
        elapsed = time.time() - start
        # 记录或监控点：elapsed
        resp_meta = {"provider": p.name, "model": model_to_use, "elapsed": elapsed}
        return {"meta": resp_meta, "response": resp}


if __name__ == "__main__":
    # 简单 demo（仅用于本地快速测试）
    mp = ModelProvider()
    print("configured providers:", list(mp.list_providers().keys()))